function deepClone(obj, hash = new WeakMap()) {
    if(obj === {}) return obj
    if (hash.has(obj)) return hash.get(obj); // 查哈希表
    if(Object.prototype.toString.call(obj) === '[object Array]') {
        let newObj = []
        hash.set(obj, newObj); // 哈希表设值
        for(let i=0; i< obj.length; i++) {
            newObj[i] = deepClone(obj[i], hash)
        }
        return newObj
    }else if(Object.prototype.toString.call(obj) === '[object Object]'){
        let newObj = {}
        hash.set(obj, newObj); // 哈希表设值
        for(let key in obj) {
            newObj[key]= deepClone(obj[key], hash)
        }
        return newObj
    }else{
        return obj
    }
}

// 解决循环引用问题
// function isObject(obj) {
//     return Object.prototype.toString.call(obj) === '[object Object]'
// }
// function deepClone4(source, hash = new WeakMap()) {

//     if (!isObject(source)) return source;
//     if (hash.has(source)) return hash.get(source); // 查哈希表
      
//     let target = Array.isArray(source) ? [] : {};
//     hash.set(source, target); // 哈希表设值
    
//     let symKeys = Object.getOwnPropertySymbols(source); // 查找
//     if (symKeys.length) { // 查找成功   
//         symKeys.forEach(symKey => {
//             if (isObject(source[symKey])) {
//                 target[symKey] = deepClone4(source[symKey], hash); // 传入哈希表
//             } else {
//                 target[symKey] = source[symKey];
//             }    
//         });
//     }
    
//     for(let key in source) {
//         if (Object.prototype.hasOwnProperty.call(source, key)) {
//             if (isObject(source[key])) {
//                 target[key] = deepClone4(source[key], hash); 
//             } else {
//                 target[key] = source[key];
//             }
//         }
//     }
//     return target;
// }
var obj = {
    a: [1,5,3,{ji: 50},10],
    b: {c: 1},
    o: null
};
obj.e = obj;
obj.a[3].wei = obj
console.log(deepClone(obj))